package net.yuyoo.uusession;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;

import com.danga.MemCached.MemCachedClient;

public class UUSession {
	
	private static final Log log = LogFactory.getLog(UUSession.class); 

	/**
	 * 创建会话的服务器
	 */
	private UUSessionServer server = null;
	
	/**
	 * 会话ID
	 */
	private String sessionId = null;
	
	/**
	 * 是否新建
	 */
	private boolean isNew = false;

	/**
	 * 会话在此实例创建时间
	 */
	private long localCreateTime = 0L;
	
 
	/**
	 * 延迟会话过期(延迟会话数据有效期)
	 * @param s -- 会话实例
	 * @return -- 是否成功
	 */
	public static boolean delaySessionTimeout(UUSession s) {
		
		boolean flag = true;
		if (null != s) {

			MemCachedClient mcc = s.server.getMemCachedClient();
			JSONObject json = s.getAttrJson();
			
			Date expiry = s.getExpiryTime();
			flag &= mcc.set(s.sessionId, json.toString(), expiry);	
			
			Iterator it = json.keys();
			String key = null;
			Object val = null;
			String attrKey = null;
			
			// --- 组装attrKeys,可以批量获取数据 ---
			String[] attrKeys = new String[json.length()];
			int idx = 0;
			while (it.hasNext()) {
				key = (String) it.next();
				attrKey = s.sessionId + key;
				attrKeys[idx] = attrKey;
				idx++;
			}
			Map<String, Object> oldVal = mcc.getMulti(attrKeys);
			Iterator oit = oldVal.keySet().iterator();
			while (oit.hasNext()) {
				key = (String) oit.next();
				val = oldVal.get(key);
				mcc.replace(key, val, expiry);
			}
		} else {
			flag = false;
		}
		return flag;		
	}
	
	UUSession(UUSessionServer server, String sessionId) {
		
		this.server = server;
		this.sessionId = sessionId;		
		this.localCreateTime = System.currentTimeMillis();
	}
	
	/**
	 * 会话ID
	 * @return -- 会话ID
	 */
	public String getId() {
		return this.sessionId;
	}
	
	/**
	 * 获取创建和包含此会好的会话服务器对象.
	 * @return -- 会话服务器
	 */
	public UUSessionServer getSessionServer() {
		return this.server;
	}
	
	/**
	 * 获取属性.
	 * @param key
	 * @return -- 属性对象.
	 */
	public Object getAttribute(String key) {
		
		if (null == key) {
			return null;
		} 
		
		String attrCode = Integer.toString(key.hashCode());		
		String attrKey = this.sessionId + attrCode;
		MemCachedClient mcc = this.server.getMemCachedClient();	 
		
		if (log.isDebugEnabled()) {
			log.debug("sessionId:" + this.sessionId);
			log.debug("attrName:" + key);
			log.debug("attrCode:" + attrCode);
			log.debug("attrKey:" + attrKey);
		}
		Object rtv = mcc.get(attrKey);
		return rtv; 
	}

	/**
	 * 获取属性名称枚举
	 * @return -- 属性名称枚举
	 */
	public Enumeration getAttributeNames() {  
		 
		JSONObject attrJson = this.getAttrJson();
		ArrayList<String> al = new ArrayList<String>(attrJson.length());
	    Iterator it = attrJson.keys();
	    while (it.hasNext()) {
	    	String elem = (String) attrJson.opt((String)it.next());
	    	al.add(elem);
	    } 
		return Collections.enumeration(al);		
	}

	
	/**
	 * 设置会话属性.
	 * @param key -- 属性名称
	 * @param value -- 属性值
	 */
	public void setAttribute(String key, Object value) {
		
		if (null == key) {
			throw new RuntimeException("Key 不能为 null");
		}

		String attrCode = Integer.toString(key.hashCode());		
		String attrKey = this.sessionId + attrCode;
		
		MemCachedClient mcc = this.server.getMemCachedClient();	  
		
		JSONObject attrJson = this.getAttrJson();
		attrJson.put(attrCode, key);

		Date expiry = this.getExpiryTime();
		mcc.set(this.sessionId, attrJson.toString(), expiry);
		mcc.set(attrKey, value, expiry);

		if (log.isDebugEnabled()) {
			log.debug("sessionId:" + this.sessionId);
			log.debug("attrJson:" + attrJson.toString());
			log.debug("attrName:" + key);
			log.debug("attrCode:" + attrCode);
			log.debug("attrKey:" + attrKey);
		}
	}
	
	/**
	 * 会话创建时间.
	 * @return -- 返回会话创建时间
	 */
	public long getCreateTime() {		
 
		Object rtv = this.getAttribute("createTime");
		if (null == rtv) {
			return this.localCreateTime;
		} else {
			long ct = Long.parseLong(rtv.toString());
			return ct; 		
		}
	}
	
	/**
	 * 获取会话过期时间
	 * @return -- 会话过期时间
	 */
	public Date getExpiryTime() {

		long now = System.currentTimeMillis();
		long liut = this.server.getLastInstanceUpdateStampTime();
		long lsut = this.server.getLastServerUpdateStampTime();
		long timeError = this.server.getTimeErrorTolerance();
		
		return new Date(now - liut + lsut + timeError + this.server.getSessionTimeout());
	}
	
	/**
	 * 最大会话交互时间.
	 * @return -- 会话过期时长.
	 */
	public int getMaxInactiveInterval() {
		return (int)this.server.getSessionTimeout();
	}
	
	/**
	 * 会话是否新建的.
	 * @return -- 是否新建标示
	 */
	public boolean isNew() {
		return this.isNew;
	}
	
	/**
	 * 删除属性
	 * @param key -- 属性名称
	 */
	public void removeAttribute(String key) {
		
		if (null != key) {
		
			String attrCode = Integer.toString(key.hashCode());
			String attrKey = this.sessionId + attrCode;
			
			JSONObject attrJson = this.getAttrJson();
			attrJson.remove(attrCode);

			MemCachedClient mcc = this.server.getMemCachedClient();
			Date expiry = this.getExpiryTime();
			mcc.set(this.sessionId, attrJson.toString(), expiry);
			mcc.delete(attrKey);
		}
	}
	
	/**
	 * 建立会话数据结构
	 * @return -- 是否创建成功
	 */
	private boolean buildSessionData() {
		
		if (null == this.sessionId) {
			this.sessionId = this.server.newSessionId();
		}
		
		
		JSONObject json = new JSONObject();		
		String attrCode = Integer.toString("createTime".hashCode());		
		json.put(attrCode, "createTime");		
		  
		
		String attrKey = this.sessionId + attrCode;
		
		boolean flag = true;

		MemCachedClient mcc = this.server.getMemCachedClient();
		Date expiry = this.getExpiryTime();
		long now = System.currentTimeMillis();
		
		flag &= mcc.set(this.sessionId, json.toString(), expiry);		 
		flag &= mcc.set(attrKey, Long.toString(now), expiry);

		this.isNew = true; 
		
		return flag;
	}
	
	/**
	 * 使当前会话无效 
	 *
	 */
	public void invalidate() {
		
		JSONObject attrJson = this.getAttrJson();
		MemCachedClient mcc = this.server.getMemCachedClient();	 		
		Iterator it = attrJson.keys();
		String attrCode = null;
		while (it.hasNext()) {
			attrCode = this.sessionId + it.next().toString();
			mcc.delete(attrCode);
		}
		mcc.delete(this.sessionId); 
	}
	
	/**
	 * 获取包含会话属性集合名称的JSON.
	 * @return -- 会话属性集合名称的JSON
	 */
	private JSONObject getAttrJson() {
		 
		MemCachedClient mcc = this.server.getMemCachedClient();	 
		Object rtv = mcc.get(this.sessionId);
		if (null == rtv) {
			this.buildSessionData();
			rtv = mcc.get(this.sessionId);
			log.debug("rtv: " + rtv);
		}
		log.debug("rtv: " + rtv);
		try {
			JSONObject attrJson = new JSONObject(rtv.toString());
			return attrJson;
		} catch (ParseException e) { 
			e.printStackTrace();
			throw new RuntimeException("此会话数据结构错误,出现无效数据,无法构建session属性");
		}		
	}
}
